package com.nxy.cpfsfe.util;


import com.adtec.starring.exception.BaseException;
import com.nxy.cpfsfe.enumtype.RespCd;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class FileUtil {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(FileUtil.class);
	
	/**
	 * 读取文件
	 * @param filePath
	 * @return
	 * @throws Exception 
	 */
	public static List<String> readFile(String filePath) throws Exception{
		return readFile(filePath,"utf-8");
	}

	public static List<String> readFile(String filePath,String charsetName) throws Exception{
		List<String> list = new ArrayList<String>();
		//加载文件信息
		File file = new File(filePath);
		//判断文件是否存在
		if(file.exists()){
			InputStreamReader inputStreamReader = null;
			try {
				inputStreamReader = new InputStreamReader(new FileInputStream(file),charsetName);
				BufferedReader buReader = new BufferedReader(inputStreamReader);
				String lines = null;
				//遍历数据信息
				while(StringUtils.isNotEmpty(lines = buReader.readLine() )){
					list.add(lines);
				}
			} catch (Exception e) {
				LOGGER.error("文件解析失败",e);
				throw new BaseException(RespCd.NCPS1005,e,"文件解析失败");
			}finally {
				if(inputStreamReader != null){
					try {
						inputStreamReader.close();
					} catch (IOException e) {
						inputStreamReader = null;
						LOGGER.error("文件输入流关闭失败",e);
						throw new Exception("文件输入流关闭失败");
					}
				}
			}
		}else{
			LOGGER.warn("文件信息不存在{{}]",filePath);
			throw new BaseException(RespCd.NCPS1005,"文件信息不存在");
		}
		return list;
	}
	
	/**
	 * 写入文件
	 * @param filePath
	 * @param list
	 * @throws Exception 
	 */
	public static void writeFile(String filePath,List<String> list) throws Exception{
		writeFile(filePath,list,false);
	}
	
	public static void writeFile(String filePath,List<String> list,boolean append) throws Exception{
		FileWriter fileWriter = null;
		BufferedWriter buWriter = null;
		try {
			//加载文件信息
			File file = new File(filePath);
			if(!file.getParentFile().exists()){
				file.getParentFile().mkdirs();
			}
			if(!file.exists()){
				file.createNewFile();
			}
			fileWriter = new FileWriter(file,append);
			buWriter = new BufferedWriter(fileWriter);
			for (String agres : list) {
				buWriter.write(agres);
				buWriter.write("\n");
			}
			buWriter.flush();
		} catch (Exception e) {
			LOGGER.error("文件写入失败",e);
			throw new BaseException(RespCd.NCPS1001,e,"文件写入失败");
		}finally{
			try {
				buWriter.close();
				fileWriter.close();
			} catch (IOException e) {
				buWriter =null;
				fileWriter = null;
				// TODO 自动生成的 catch 块
				LOGGER.error("文件写入流关闭失败",e);
				throw new Exception("文件写入流关闭失败");
			}
		}
	}
	
	/**
	 * 
	 * Description:删除指定文件或指定目录以及该目录下所有文件
	 *
	 * @author jjw
	 * @data 2019年8月29日
	 */
	public static boolean delFile(File file){
		
		if(!file.exists()){
			return false;
		}
		
		if(file.isDirectory()){
			File[] files = file.listFiles();
			for(File f : files){
				delFile(f);
			}
		}
		
		return file.delete();
		
	}
	
	/**
	 * 
	 * Description:将多个文件或目录（以及目录中文件）压缩到指定tar包中
	 *
	 * @author jjw
	 * @data 2019年9月2日
	 */
	public static void tarFile(String[] filePaths,String tarFilePath){

		tarFile(filePaths,"UTF-8",tarFilePath,"UTF-8");

	}

	public static void tarFile(String[] filePaths,String fileCharsetName,String tarFilePath,String tarCharsetName){
		
		boolean delTar = false;
		FileOutputStream fos = null;
		TarArchiveOutputStream taos = null;
		
		File tarFile = new File(tarFilePath);
		if(tarFile.isDirectory()){
			String errMsg = String.format("TAR-[%s]不是一个文件!", tarFilePath);
			throw new BaseException(RespCd.NCPS9400, errMsg);
		}
		
		if(!tarFile.getParentFile().exists()){
			tarFile.getParentFile().mkdirs();
		}
		
		try{
			fos = new FileOutputStream(tarFilePath);
			taos = new TarArchiveOutputStream(fos);
			
			for(String filePath : filePaths){
				doTarFile(new File(filePath),"",taos,fileCharsetName,tarCharsetName);
			}
		}catch(Exception e){
			delTar = true;
			String errMsg = String.format("TAR-压缩tar文件[%s]出错", tarFilePath);
			throw new BaseException(RespCd.NCPS9400,e,errMsg);
		}finally{
			if(taos != null){
				try {
					taos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
			if(fos != null){
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
			if(delTar){
				delFile(tarFile);
				LOGGER.info("{}文件已删除",tarFilePath);
			}
		}
		
	}
	
	/**
	 * 
	 * Description:压缩方法
	 *
	 * @author jjw
	 * @data 2019年9月2日
	 */
	private static void doTarFile(File file,String parentDirName,TarArchiveOutputStream taos,String fileCharsetName,String tarCharsetName){
		
		if(!file.exists()){
			String errMsg = String.format("TAR-目标文件或目录[%s]不存在!", file.getAbsoluteFile());
			throw new BaseException(RespCd.NCPS9400, errMsg);
		}
		
		String deepPath = parentDirName + file.getName();
		if(file.isDirectory()){
			try{
				TarArchiveEntry tae = new TarArchiveEntry(file);
				tae.setName(new String(deepPath.getBytes("UTF-8"),"UTF-8"));
				taos.putArchiveEntry(tae);
			}catch(Exception e){
				String errMsg = String.format("TAR-压缩[%s]文件出错", file.getAbsolutePath());
				throw new BaseException(RespCd.NCPS9400,e,errMsg);
			}finally{
				try {
					taos.closeArchiveEntry();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
			File[] childFiles = file.listFiles();
			if(childFiles.length >= 1){
				for(File childFile : childFiles){
					doTarFile(childFile,deepPath + File.separator,taos,fileCharsetName,tarCharsetName);
				}
			}
			
			return;
		}

		FileInputStream fis = null;
		BufferedReader br = null;
		try {
			TarArchiveEntry tae = new TarArchiveEntry(file);
			tae.setName(new String(deepPath.getBytes("UTF-8"),"UTF-8"));
			tae.setSize(getTransCodeSize(file,fileCharsetName,tarCharsetName));
			taos.putArchiveEntry(tae);
			fis = new FileInputStream(file);
			br = new BufferedReader(new InputStreamReader(fis,fileCharsetName));

			String line = null;
			while((line = br.readLine()) != null){
				line += "\n";
				taos.write(line.getBytes(tarCharsetName));
			}
			taos.flush();
		} catch (Exception e) {
			String errMsg = String.format("TAR-压缩[%s]文件出错", file.getAbsolutePath());
			throw new BaseException(RespCd.NCPS9400,e,errMsg);
		}finally{
			try {
				taos.closeArchiveEntry();
			} catch (IOException e) {
				e.printStackTrace();
			}

			if(br != null){
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			
			if(fis != null){
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		
	}

	/**
	 *	获取文件转码后的大小
	 */
	private static long getTransCodeSize(File file,String sCode,String tCode) throws Exception{

		long size = 0;

		FileInputStream fis = null;
		BufferedReader br = null;

		try{
			fis = new FileInputStream(file);
			br = new BufferedReader(new InputStreamReader(fis,sCode));

			String line = null;
			while((line = br.readLine()) != null){
				line += "\n";
				size += line.getBytes(tCode).length;
			}

			return size;
		}finally {
			if(br != null){
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			if(fis != null){
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}
	
	/**
	 * 
	 * Description:解压tar包到指定目录
	 *
	 * @author jjw
	 * @data 2019年8月29日
	 */
	public static void deTarFile(String tarFilePath,String destPath){

		deTarFile(tarFilePath,"UTF-8",destPath,"UTF-8");

	}

	public static void deTarFile(String tarFilePath,String tarCharsetName,String destPath,String destCharsetName){

		FileInputStream fis = null;
		TarArchiveInputStream tais = null;
		BufferedReader br = null;
		FileOutputStream fos;
		BufferedWriter bw;

		File tarFile = new File(tarFilePath);
		if(!tarFile.exists()){
			String errMsg = String.format("TAR-目标文件[%s]不存在!", tarFilePath);
			throw new BaseException(RespCd.NCPS9400, errMsg);
		}else if(tarFile.isDirectory()){
			String errMsg = String.format("TAR-目标文件[%s]不是一个文件!", tarFilePath);
			throw new BaseException(RespCd.NCPS9400, errMsg);
		}

		File destDir = new File(destPath);
		if(destDir.isFile()){
			String errMsg = String.format("TAR-[%s]不是一个目录!", destPath);
			throw new BaseException(RespCd.NCPS9400, errMsg);
		}else{
			if(!destDir.exists()){
				destDir.mkdirs();
			}
		}

		try{
			LOGGER.info("开始解压[{}]文件",tarFilePath);
			fis = new FileInputStream(tarFilePath);
			tais = new TarArchiveInputStream(fis);
			br = new BufferedReader(new InputStreamReader(tais,tarCharsetName));
			TarArchiveEntry tae = null;

			//遍历tar包中所有文件
			while((tae = tais.getNextTarEntry()) != null){
				fos = null;
				bw = null;
				try{
					String finalPath = destPath + File.separator + tae.getName();
					File finalFile = new File(finalPath);

					if(finalFile.exists()){
						if(tae.isDirectory()){
							continue;
						}
					}else{
						if(tae.isDirectory()){
							finalFile.mkdir();
							continue;
						}
					}

					fos = new FileOutputStream(finalFile);
					bw = new BufferedWriter(new OutputStreamWriter(fos,destCharsetName));
					String line = null;
					while((line = br.readLine()) != null){
						line += "\n";
						bw.write(line);
					}
					bw.flush();
				}finally {
					if(bw != null){
						try {
							bw.close();
						} catch (IOException e1) {
							e1.printStackTrace();
						}
					}

					if(fos != null){
						try {
							fos.close();
						} catch (IOException e1) {
							e1.printStackTrace();
						}
					}
				}
			}
			LOGGER.info("[{}]文件解压完成",tarFilePath);
		}catch(Exception e){
			String errMsg = String.format("TAR-解压文件[%s]出错!", tarFilePath);
			throw new BaseException(RespCd.NCPS9400,e,errMsg);
		}finally{
			if(br != null){
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			if(tais != null){
				try {
					tais.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

			if(fis != null){
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
}
